The goal of this analysis is to determine what name is in primary use at this stage for DOID:6457. Multiple terms exist that appear to be equivalent (see issue #1514) and there are numerous names for this disease.

data_dir <- here::here("data/disease_info")
data_file <- file.path(data_dir, "onyong-nyong-fever.rda")

if (!dir.exists(data_dir)) dir.create(data_dir, recursive = TRUE)
# get_ftxt_safely() will automatically get PMC articles or books and will NOT
#   fail if on errors caused by individual download failures
safe_epmc_ftxt <- purrr::safely(europepmc::epmc_ftxt, otherwise = NA, quiet = FALSE)
safe_epmc_ftxt_bk <- purrr::safely(europepmc::epmc_ftxt_book, otherwise = NA, quiet = FALSE)

get_ftxt_safely <- function(pmcid = NA, bookid = NA) {
    if (is.na(pmcid) && is.na(bookid) ) return(NA)
    if (!is.na(pmcid)) {
        out <- list(safe_epmc_ftxt(pmcid))
    } else {
        out <- list(safe_epmc_ftxt_bk(bookid))
    }
    cat(".")
    out
}


# parse_ftxt_xml() parses results from get_ftxt_safely()
parse_ftxt_xml <- function(safe_ftxt_xml, xml_accessor) {
    if (!is.null(safe_ftxt_xml$error)) {
        return(paste0("ERROR: ", safe_ftxt_xml$error$message))
    }
    out <- safe_ftxt_xml$result |>
        xml2::xml_find_all(xml_accessor) |>
        xml2::xml_text()

    if (length(out) == 0) {
        out <- paste0(
            "ERROR [NO BODY]: ",
            xml2::xml_text(safe_ftxt_xml$result)
        )
        if (length(out) == 0) {
            out <- "ERROR: No text extractable"
        }
    } else if (length(out) > 1) {
        out <- DO.utils::vctr_to_string(out, delim = "%%%%%") |>
            paste0("WARNING: Multilength output, separated by %%%%%.")
    }

    out
}

These are the terms currently in DO, or that have been identified in initial searches.

terms <- c(
    "O'nyong'nyong fever", # current label
    "O'nyong-nyong",
    "o'nyong-nyong"
)

Begin by searching EuropePMC for articles that contain one or more exact matches to these terms using the default search. Save output to file, to avoid potential of repeat API call.

# exclude abbreviations when searching for publications (too likely to 
search_str <- paste0(
    'OPEN_ACCESS:y AND (',
    paste0('"', terms[stringr::str_length(terms) > 4] , '"', collapse = " OR "),
    ')'
)

if (!file.exists(data_file)) {
    res <- europepmc::epmc_search(search_str, synonym = FALSE, limit = 20000)

    save(res, file = data_file)
} else {
    load(data_file)
}

The number of publication hits (NULL) can be reasonably be processed using all the full text articles, excluding preprints and retractions.

res_tidy <- res |>
    dplyr::filter(!stringr::str_detect(pubType, "retract|preprint")) |>
    dplyr::select(
        "id", "title", "pubYear", pubDate = "firstPublicationDate", "pmcid"
    ) |>
    dplyr::mutate(
        pubDate = lubridate::as_date(pubDate),
        pubYear = lubridate::year(pubDate)
    )

if (!exists("res_ftxt")) {
    res_ftxt <- res_tidy |>
        dplyr::rowwise() |>
        dplyr::mutate(ft_xml = get_ftxt_safely(pmcid)) |>
        dplyr::mutate(ft = parse_ftxt_xml(ft_xml, "//body"))
    
    save(res, res_ftxt, file = data_file)
}

Evaluating Usage

Extracting all these values from the full text of the sample publications and all the titles (in a case-insensitive manner).

regex_str <- "o.nyong.nyong( fever)?"
term_df <- res_tidy |>
    dplyr::left_join(
        res_ftxt,
        by = c("id", "title", "pubYear", "pubDate", "pmcid")
    ) |>
    dplyr::select("id", "pubDate", "title", "ft") |>
    dplyr::mutate(
        title_match = stringr::str_extract_all(
            .data$title,
            stringr::regex(regex_str, ignore_case = TRUE)
        ),
        ft_match = stringr::str_extract_all(
            .data$ft,
            stringr::regex(regex_str, ignore_case = TRUE)
        )
    ) |>
    tidyr::unnest(title_match, keep_empty = TRUE) |>
    tidyr::unnest(ft_match, keep_empty = TRUE) |>
    dplyr::mutate(ft = !is.na(ft))

The number of publications with and without matches in their titles or full text, noting whether their full-text was obtained are as follows:

term_df |>
    dplyr::summarize(
        title_match = any(!is.na(title_match)),
        ft_match = any(!is.na(ft_match)),
        ft = unique(ft),
        .by = "id"
    ) |>
    dplyr::count(ft, title_match, ft_match) |>
    dplyr::mutate(pct = round(n / sum(n) * 100, 2)) |>
    dplyr::rename(ft_obtained = "ft")

Any non-matches will just be dropped for the analysis of names, and special quote or dash marks will be standardized to '.

matches <- term_df |>
    tidyr::pivot_longer(
        title_match:ft_match,
        names_to = c("source", ".value"),
        names_sep = "_",
        values_drop_na = TRUE
    ) |>
    dplyr::mutate(
        match = stringr::str_replace_all(
            .data$match,
            c("['‘’′]" = "'", "[-‐–]" = "-")
        ),
        match_lc = stringr::str_to_lower(.data$match)
    ) |>
    dplyr::select(-"title")

The number of case-insenitive matches in the titles and full text are as follows:

matches |>
    DO.utils::collapse_col("match") |>
    dplyr::count(.data$source, .data$match_lc)

The number of matches, in the full text only, preserving case are as follows:

ft_matches <- matches |>
    dplyr::filter(.data$source == "ft")

ft_matches |>
    DO.utils::collapse_col("match_lc") |> 
    dplyr::count(.data$match, sort = TRUE)

The current name in DO is pretty low in the list and doesn’t match the original. The top two are the original, with the second being the original capitalization. The uppercase version is much more common. It’s much less common to find the name with “fever” but that’s probably to be expected since the name of the virus will almost certainly be used at least once with each disease reference, and often much more.

Organized by publication date and binned into year intervals (limited to the top ten), the results are as follows:

g_colors <- hues::iwanthue(dplyr::n_distinct(ft_matches$match))

ft_matches |>
    DO.utils::collapse_col("match_lc") |>
    dplyr::mutate(n = length(.data$source), .by = "match") |>
    ggplot2::ggplot() +
    ggplot2::geom_freqpoly(
        ggplot2::aes(x = pubDate, color = match),
        binwidth = 365
    ) +
    ggplot2::scale_color_manual(values = g_colors) +
    ggplot2::facet_wrap(~ source, ncol = 1, scales = "free_y")

Hmm… the oldest uses are quite a long time ago and make the graph a bit hard to read. Subsetting the graph to after the year 2000:

g <- ft_matches |>
    DO.utils::collapse_col("match_lc") |>
    dplyr::mutate(n = length(.data$source), .by = "match") |>
    ggplot2::ggplot() +
    ggplot2::geom_freqpoly(
        ggplot2::aes(x = pubDate, color = match, group = match),
        binwidth = 365,
        linewidth = 1
    ) +
    ggplot2::scale_color_manual(values = g_colors) +
    ggplot2::scale_x_date(
        date_breaks = "5 years",
        date_labels = "%Y"
    ) +
    ggplot2::facet_wrap(~ source, ncol = 1, scales = "free_y") +
    ggplot2::coord_cartesian(
        xlim = c(as.Date("2000-01-01"), as.Date("2025-01-01"))
    ) +
    ggplot2::theme_minimal()

plotly::ggplotly(g)

Based on this, it’s very clear that the capitalized version of the original name is most common. Just looking at the disease name just to be sure this is also the case for the disease:

g <- ft_matches |>
    dplyr::filter(stringr::str_detect(.data$match, "ever")) |>
    DO.utils::collapse_col("match_lc") |>
    dplyr::mutate(n = length(.data$source), .by = "match") |>
    ggplot2::ggplot() +
    ggplot2::geom_freqpoly(
        ggplot2::aes(x = pubDate, color = match, group = match),
        binwidth = 365,
        linewidth = 1
    ) +
    ggplot2::scale_color_manual(values = g_colors) +
    ggplot2::scale_x_date(
        date_breaks = "5 years",
        date_labels = "%Y"
    ) +
    ggplot2::facet_wrap(~ source, ncol = 1, scales = "free_y") +
    ggplot2::theme_minimal()

plotly::ggplotly(g)

A general sum would be more useful but the differences there are negligible. In this case, it makes sense to follow the most common name for the virus.

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgRE9JRDo2NDU3IG5hbWUgJiBzeW5vbnltcyIKZGF0ZTogIjIwMjUtMDItMjEiCm91dHB1dDoKICAgIGh0bWxfbm90ZWJvb2s6CiAgICAgICAgdG9jOiB0cnVlCiAgICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKVGhlIGdvYWwgb2YgdGhpcyBhbmFseXNpcyBpcyB0byBkZXRlcm1pbmUgd2hhdCBuYW1lIGlzIGluIHByaW1hcnkgdXNlIGF0IHRoaXMgc3RhZ2UgZm9yIERPSUQ6NjQ1Ny4gTXVsdGlwbGUgdGVybXMgZXhpc3QgdGhhdCBhcHBlYXIgdG8gYmUgZXF1aXZhbGVudCAoc2VlIGlzc3VlIFsjMTUxNF0oaHR0cHM6Ly9naXRodWIuY29tL0Rpc2Vhc2VPbnRvbG9neS9IdW1hbkRpc2Vhc2VPbnRvbG9neS9pc3N1ZXMvMTUxNCkpIGFuZCB0aGVyZSBhcmUgbnVtZXJvdXMgbmFtZXMgZm9yIHRoaXMgZGlzZWFzZS4KCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShldXJvcGVwbWMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHhtbDIpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShodWVzKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpgYGB7ciBpbl9wcm9ncmVzc19kYXRhfQpkYXRhX2RpciA8LSBoZXJlOjpoZXJlKCJkYXRhL2Rpc2Vhc2VfaW5mbyIpCmRhdGFfZmlsZSA8LSBmaWxlLnBhdGgoZGF0YV9kaXIsICJjb3dkZW5fc3luZHJvbWVfMS5yZGEiKQoKaWYgKCFkaXIuZXhpc3RzKGRhdGFfZGlyKSkgZGlyLmNyZWF0ZShkYXRhX2RpciwgcmVjdXJzaXZlID0gVFJVRSkKYGBgCgpgYGB7ciBjdXN0b21fZnVuY3Rpb25zfQojIGdldF9mdHh0X3NhZmVseSgpIHdpbGwgYXV0b21hdGljYWxseSBnZXQgUE1DIGFydGljbGVzIG9yIGJvb2tzIGFuZCB3aWxsIE5PVAojICAgZmFpbCBpZiBvbiBlcnJvcnMgY2F1c2VkIGJ5IGluZGl2aWR1YWwgZG93bmxvYWQgZmFpbHVyZXMKc2FmZV9lcG1jX2Z0eHQgPC0gcHVycnI6OnNhZmVseShldXJvcGVwbWM6OmVwbWNfZnR4dCwgb3RoZXJ3aXNlID0gTkEsIHF1aWV0ID0gRkFMU0UpCnNhZmVfZXBtY19mdHh0X2JrIDwtIHB1cnJyOjpzYWZlbHkoZXVyb3BlcG1jOjplcG1jX2Z0eHRfYm9vaywgb3RoZXJ3aXNlID0gTkEsIHF1aWV0ID0gRkFMU0UpCgpnZXRfZnR4dF9zYWZlbHkgPC0gZnVuY3Rpb24ocG1jaWQgPSBOQSwgYm9va2lkID0gTkEpIHsKICAgIGlmIChpcy5uYShwbWNpZCkgJiYgaXMubmEoYm9va2lkKSApIHJldHVybihOQSkKICAgIGlmICghaXMubmEocG1jaWQpKSB7CiAgICAgICAgb3V0IDwtIGxpc3Qoc2FmZV9lcG1jX2Z0eHQocG1jaWQpKQogICAgfSBlbHNlIHsKICAgICAgICBvdXQgPC0gbGlzdChzYWZlX2VwbWNfZnR4dF9iayhib29raWQpKQogICAgfQogICAgY2F0KCIuIikKICAgIG91dAp9CgoKIyBwYXJzZV9mdHh0X3htbCgpIHBhcnNlcyByZXN1bHRzIGZyb20gZ2V0X2Z0eHRfc2FmZWx5KCkKcGFyc2VfZnR4dF94bWwgPC0gZnVuY3Rpb24oc2FmZV9mdHh0X3htbCwgeG1sX2FjY2Vzc29yKSB7CiAgICBpZiAoIWlzLm51bGwoc2FmZV9mdHh0X3htbCRlcnJvcikpIHsKICAgICAgICByZXR1cm4ocGFzdGUwKCJFUlJPUjogIiwgc2FmZV9mdHh0X3htbCRlcnJvciRtZXNzYWdlKSkKICAgIH0KICAgIG91dCA8LSBzYWZlX2Z0eHRfeG1sJHJlc3VsdCB8PgogICAgICAgIHhtbDI6OnhtbF9maW5kX2FsbCh4bWxfYWNjZXNzb3IpIHw+CiAgICAgICAgeG1sMjo6eG1sX3RleHQoKQoKICAgIGlmIChsZW5ndGgob3V0KSA9PSAwKSB7CiAgICAgICAgb3V0IDwtIHBhc3RlMCgKICAgICAgICAgICAgIkVSUk9SIFtOTyBCT0RZXTogIiwKICAgICAgICAgICAgeG1sMjo6eG1sX3RleHQoc2FmZV9mdHh0X3htbCRyZXN1bHQpCiAgICAgICAgKQogICAgICAgIGlmIChsZW5ndGgob3V0KSA9PSAwKSB7CiAgICAgICAgICAgIG91dCA8LSAiRVJST1I6IE5vIHRleHQgZXh0cmFjdGFibGUiCiAgICAgICAgfQogICAgfSBlbHNlIGlmIChsZW5ndGgob3V0KSA+IDEpIHsKICAgICAgICBvdXQgPC0gRE8udXRpbHM6OnZjdHJfdG9fc3RyaW5nKG91dCwgZGVsaW0gPSAiJSUlJSUiKSB8PgogICAgICAgICAgICBwYXN0ZTAoIldBUk5JTkc6IE11bHRpbGVuZ3RoIG91dHB1dCwgc2VwYXJhdGVkIGJ5ICUlJSUlLiIpCiAgICB9CgogICAgb3V0Cn0KYGBgCgoKVGhlc2UgYXJlIHRoZSB0ZXJtcyBjdXJyZW50bHkgaW4gRE8sIG9yIHRoYXQgaGF2ZSBiZWVuIGlkZW50aWZpZWQgaW4gaW5pdGlhbCBzZWFyY2hlcy4KCmBgYHtyfQp0ZXJtcyA8LSBjKAogICAgIlBURU4gaGFtYXJ0b21hIHR1bW9yIHN5bmRyb21lIiwgIyBjdXJyZW50IGxhYmVsCiAgICAiQmFubmF5YW4tUmlsZXktUnV2YWxjYWJhIHN5bmRyb21lIiwKICAgICJCYW5uYXlhbi1ab25hbmEgc3luZHJvbWUiLAogICAgIkNvd2RlbiBzeW5kcm9tZSAxIiwKICAgICJSaWxleS1TbWl0aCBzeW5kcm9tZSIsCiAgICAiUnV2YWxjYWJhLU15aHJlLVNtaXRoIHN5bmRyb21lIiwKICAgICMgYWRkaXRpb25hbCBmcm9tIE9NSU0gKG5vdCBpbiBETykKICAgICJtdWx0aXBsZSBoYW1hcnRvbWEgc3luZHJvbWUiLAogICAgIlBURU4gaGFtYXJ0b21hIHR1bW9yIHN5bmRyb21lIHdpdGggZ3JhbnVsYXIgY2VsbCB0dW1vciIsCiAgICAibWFjcm9jZXBoYWx5LCBwc2V1ZG9wYXBpbGxlZGVtYSwgYW5kIG11bHRpcGxlIGhlbWFuZ2lvbWF0YSIsCiAgICAibWFjcm9jZXBoYWx5LCBtdWx0aXBsZSBsaXBvbWFzLCBhbmQgaGVtYW5naW9tYXRhICIsCikKCmluaXRpYWxpc20gPC0gYygiUk1TUyIsICJCWlMiLCAiUEhUUyIsICJNSEFNIiwgIkJCUlMiLCAiQ1dTMSIsICJDUyIsICJDRCIpCmBgYAoKCkJlZ2luIGJ5IHNlYXJjaGluZyBFdXJvcGVQTUMgZm9yIGFydGljbGVzIHRoYXQgY29udGFpbiBvbmUgb3IgbW9yZSBleGFjdCBtYXRjaGVzIHRvIHRoZXNlIHRlcm1zIHVzaW5nIHRoZSBkZWZhdWx0IHNlYXJjaC4gX1NhdmUgb3V0cHV0IHRvIGZpbGUsIHRvIGF2b2lkIHBvdGVudGlhbCBvZiByZXBlYXQgQVBJIGNhbGwuXwoKYGBge3J9CiMgZXhjbHVkZSBhYmJyZXZpYXRpb25zIHdoZW4gc2VhcmNoaW5nIGZvciBwdWJsaWNhdGlvbnMgKHRvbyBsaWtlbHkgdG8gCm5tX3NlYXJjaCA8LSBwYXN0ZTAoCiAgICAnIicsIHRlcm1zW3N0cmluZ3I6OnN0cl9sZW5ndGgodGVybXMpID4gNF0gLCAnIicsCiAgICBjb2xsYXBzZSA9ICIgT1IgIgopCnNlYXJjaF9zdHIgPC0gcGFzdGUwKCdPUEVOX0FDQ0VTUzp5IEFORCAoJywgbm1fc2VhcmNoLCAnKScpCgppZiAoIWZpbGUuZXhpc3RzKGRhdGFfZmlsZSkpIHsKICAgIHJlcyA8LSBldXJvcGVwbWM6OmVwbWNfc2VhcmNoKHNlYXJjaF9zdHIsIHN5bm9ueW0gPSBGQUxTRSwgbGltaXQgPSAyMDAwMCkKICAgIHJlc19pbml0IDwtIHB1cnJyOjptYXAoCiAgICAgICAgaW5pdGlhbGlzbSwKICAgICAgICBmdW5jdGlvbiguaW5pdCkgewogICAgICAgICAgICBpbml0X3NlYXJjaCA8LSBETy51dGlsczo6c2FuZHdpY2hfdGV4dCguaW5pdCwgJyInKQogICAgICAgICAgICBub19ubSA8LSBldXJvcGVwbWM6OmVwbWNfc2VhcmNoKAogICAgICAgICAgICAgICAgaW5pdF9zZWFyY2gsCiAgICAgICAgICAgICAgICBzeW5vbnltID0gRkFMU0UsCiAgICAgICAgICAgICAgICBsaW1pdCA9IDIwMDAwCiAgICAgICAgICAgICkKICAgICAgICAgICAgd19ubSA8LSBldXJvcGVwbWM6OmVwbWNfc2VhcmNoKAogICAgICAgICAgICAgICAgcGFzdGUwKGluaXRfc2VhcmNoLCAiIEFORCAoIiwgbm1fc2VhcmNoLCAiKSIpLAogICAgICAgICAgICAgICAgc3lub255bSA9IEZBTFNFLAogICAgICAgICAgICAgICAgbGltaXQgPSAyMDAwMAogICAgICAgICAgICApCiAgICAgICAgfSAKICAgICkKICAgIHNhdmUocmVzLCByZXNfaW5pdCwgZmlsZSA9IGRhdGFfZmlsZSkKfSBlbHNlIHsKICAgIGxvYWQoZGF0YV9maWxlKQp9CmBgYAoKVGhlIG51bWJlciBvZiBwdWJsaWNhdGlvbiBoaXRzIChgciBmb3JtYXQobnJvdyhyZXMpLCBiaWcubWFyayA9ICIsIilgKSBjYW4gYmUgcmVhc29uYWJseSBiZSBwcm9jZXNzZWQgdXNpbmcgYWxsIHRoZSBmdWxsIHRleHQgYXJ0aWNsZXMsIGV4Y2x1ZGluZyBwcmVwcmludHMgYW5kIHJldHJhY3Rpb25zLgoKYGBge3J9CnJlc190aWR5IDwtIHJlcyB8PgogICAgZHBseXI6OmZpbHRlcighc3RyaW5ncjo6c3RyX2RldGVjdChwdWJUeXBlLCAicmV0cmFjdHxwcmVwcmludCIpKSB8PgogICAgZHBseXI6OnNlbGVjdCgKICAgICAgICAiaWQiLCAidGl0bGUiLCAicHViWWVhciIsIHB1YkRhdGUgPSAiZmlyc3RQdWJsaWNhdGlvbkRhdGUiLCAicG1jaWQiCiAgICApIHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgIHB1YkRhdGUgPSBsdWJyaWRhdGU6OmFzX2RhdGUocHViRGF0ZSksCiAgICAgICAgcHViWWVhciA9IGx1YnJpZGF0ZTo6eWVhcihwdWJEYXRlKQogICAgKQoKaWYgKCFleGlzdHMoInJlc19mdHh0IikpIHsKICAgIHJlc19mdHh0IDwtIHJlc190aWR5IHw+CiAgICAgICAgZHBseXI6OnJvd3dpc2UoKSB8PgogICAgICAgIGRwbHlyOjptdXRhdGUoZnRfeG1sID0gZ2V0X2Z0eHRfc2FmZWx5KHBtY2lkKSkgfD4KICAgICAgICBkcGx5cjo6bXV0YXRlKGZ0ID0gcGFyc2VfZnR4dF94bWwoZnRfeG1sLCAiLy9ib2R5IikpCiAgICAKICAgIHNhdmUocmVzLCByZXNfZnR4dCwgZmlsZSA9IGRhdGFfZmlsZSkKfQpgYGAKCgojIEV2YWx1YXRpbmcgVXNhZ2UKCkV4dHJhY3RpbmcgYWxsIHRoZXNlIHZhbHVlcyBmcm9tIHRoZSBmdWxsIHRleHQgb2YgdGhlIHNhbXBsZSBwdWJsaWNhdGlvbnMgYW5kIGFsbCB0aGUgdGl0bGVzIChpbiBhIGNhc2UtaW5zZW5zaXRpdmUgbWFubmVyKS4KYGBge3J9CnJlZ2V4X3N0ciA8LSAiby5ueW9uZy5ueW9uZyggZmV2ZXIpPyIKdGVybV9kZiA8LSByZXNfdGlkeSB8PgogICAgZHBseXI6OmxlZnRfam9pbigKICAgICAgICByZXNfZnR4dCwKICAgICAgICBieSA9IGMoImlkIiwgInRpdGxlIiwgInB1YlllYXIiLCAicHViRGF0ZSIsICJwbWNpZCIpCiAgICApIHw+CiAgICBkcGx5cjo6c2VsZWN0KCJpZCIsICJwdWJEYXRlIiwgInRpdGxlIiwgImZ0IikgfD4KICAgIGRwbHlyOjptdXRhdGUoCiAgICAgICAgdGl0bGVfbWF0Y2ggPSBzdHJpbmdyOjpzdHJfZXh0cmFjdF9hbGwoCiAgICAgICAgICAgIC5kYXRhJHRpdGxlLAogICAgICAgICAgICBzdHJpbmdyOjpyZWdleChyZWdleF9zdHIsIGlnbm9yZV9jYXNlID0gVFJVRSkKICAgICAgICApLAogICAgICAgIGZ0X21hdGNoID0gc3RyaW5ncjo6c3RyX2V4dHJhY3RfYWxsKAogICAgICAgICAgICAuZGF0YSRmdCwKICAgICAgICAgICAgc3RyaW5ncjo6cmVnZXgocmVnZXhfc3RyLCBpZ25vcmVfY2FzZSA9IFRSVUUpCiAgICAgICAgKQogICAgKSB8PgogICAgdGlkeXI6OnVubmVzdCh0aXRsZV9tYXRjaCwga2VlcF9lbXB0eSA9IFRSVUUpIHw+CiAgICB0aWR5cjo6dW5uZXN0KGZ0X21hdGNoLCBrZWVwX2VtcHR5ID0gVFJVRSkgfD4KICAgIGRwbHlyOjptdXRhdGUoZnQgPSAhaXMubmEoZnQpKQpgYGAKClRoZSBudW1iZXIgb2YgcHVibGljYXRpb25zIHdpdGggYW5kIHdpdGhvdXQgbWF0Y2hlcyBpbiB0aGVpciB0aXRsZXMgb3IgZnVsbCB0ZXh0LCBub3Rpbmcgd2hldGhlciB0aGVpciBmdWxsLXRleHQgd2FzIG9idGFpbmVkIGFyZSBhcyBmb2xsb3dzOgoKYGBge3J9CnRlcm1fZGYgfD4KICAgIGRwbHlyOjpzdW1tYXJpemUoCiAgICAgICAgdGl0bGVfbWF0Y2ggPSBhbnkoIWlzLm5hKHRpdGxlX21hdGNoKSksCiAgICAgICAgZnRfbWF0Y2ggPSBhbnkoIWlzLm5hKGZ0X21hdGNoKSksCiAgICAgICAgZnQgPSB1bmlxdWUoZnQpLAogICAgICAgIC5ieSA9ICJpZCIKICAgICkgfD4KICAgIGRwbHlyOjpjb3VudChmdCwgdGl0bGVfbWF0Y2gsIGZ0X21hdGNoKSB8PgogICAgZHBseXI6Om11dGF0ZShwY3QgPSByb3VuZChuIC8gc3VtKG4pICogMTAwLCAyKSkgfD4KICAgIGRwbHlyOjpyZW5hbWUoZnRfb2J0YWluZWQgPSAiZnQiKQpgYGAKQW55IG5vbi1tYXRjaGVzIHdpbGwganVzdCBiZSBkcm9wcGVkIGZvciB0aGUgYW5hbHlzaXMgb2YgbmFtZXMsIGFuZCBzcGVjaWFsIHF1b3RlIG9yIGRhc2ggbWFya3Mgd2lsbCBiZSBzdGFuZGFyZGl6ZWQgdG8gYCdgLgoKYGBge3J9Cm1hdGNoZXMgPC0gdGVybV9kZiB8PgogICAgdGlkeXI6OnBpdm90X2xvbmdlcigKICAgICAgICB0aXRsZV9tYXRjaDpmdF9tYXRjaCwKICAgICAgICBuYW1lc190byA9IGMoInNvdXJjZSIsICIudmFsdWUiKSwKICAgICAgICBuYW1lc19zZXAgPSAiXyIsCiAgICAgICAgdmFsdWVzX2Ryb3BfbmEgPSBUUlVFCiAgICApIHw+CiAgICBkcGx5cjo6bXV0YXRlKAogICAgICAgIG1hdGNoID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKAogICAgICAgICAgICAuZGF0YSRtYXRjaCwKICAgICAgICAgICAgYygiWyfigJjigJnigLJdIiA9ICInIiwgIlst4oCQ4oCTXSIgPSAiLSIpCiAgICAgICAgKSwKICAgICAgICBtYXRjaF9sYyA9IHN0cmluZ3I6OnN0cl90b19sb3dlciguZGF0YSRtYXRjaCkKICAgICkgfD4KICAgIGRwbHlyOjpzZWxlY3QoLSJ0aXRsZSIpCmBgYAoKVGhlIG51bWJlciBvZiBjYXNlLWluc2VuaXRpdmUgbWF0Y2hlcyBpbiB0aGUgdGl0bGVzIGFuZCBmdWxsIHRleHQgYXJlIGFzIGZvbGxvd3M6CmBgYHtyfQptYXRjaGVzIHw+CiAgICBETy51dGlsczo6Y29sbGFwc2VfY29sKCJtYXRjaCIpIHw+CiAgICBkcGx5cjo6Y291bnQoLmRhdGEkc291cmNlLCAuZGF0YSRtYXRjaF9sYykKYGBgCgpUaGUgbnVtYmVyIG9mIG1hdGNoZXMsIGluIHRoZSBmdWxsIHRleHQgb25seSwgcHJlc2VydmluZyBjYXNlIGFyZSBhcyBmb2xsb3dzOgpgYGB7cn0KZnRfbWF0Y2hlcyA8LSBtYXRjaGVzIHw+CiAgICBkcGx5cjo6ZmlsdGVyKC5kYXRhJHNvdXJjZSA9PSAiZnQiKQoKZnRfbWF0Y2hlcyB8PgogICAgRE8udXRpbHM6OmNvbGxhcHNlX2NvbCgibWF0Y2hfbGMiKSB8PiAKICAgIGRwbHlyOjpjb3VudCguZGF0YSRtYXRjaCwgc29ydCA9IFRSVUUpCmBgYAoKVGhlIGN1cnJlbnQgbmFtZSBpbiBETyBpcyBwcmV0dHkgbG93IGluIHRoZSBsaXN0IGFuZCBkb2Vzbid0IG1hdGNoIHRoZSBvcmlnaW5hbC4gVGhlIHRvcCB0d28gYXJlIHRoZSBvcmlnaW5hbCwgd2l0aCB0aGUgc2Vjb25kIGJlaW5nIHRoZSBvcmlnaW5hbCBjYXBpdGFsaXphdGlvbi4gVGhlIHVwcGVyY2FzZSB2ZXJzaW9uIGlzIG11Y2ggbW9yZSBjb21tb24uIEl0J3MgbXVjaCBsZXNzIGNvbW1vbiB0byBmaW5kIHRoZSBuYW1lIHdpdGggImZldmVyIiBidXQgdGhhdCdzIHByb2JhYmx5IHRvIGJlIGV4cGVjdGVkIHNpbmNlIHRoZSBuYW1lIG9mIHRoZSB2aXJ1cyB3aWxsIGFsbW9zdCBjZXJ0YWlubHkgYmUgdXNlZCBhdCBsZWFzdCBvbmNlIHdpdGggZWFjaCBkaXNlYXNlIHJlZmVyZW5jZSwgYW5kIG9mdGVuIG11Y2ggbW9yZS4KCk9yZ2FuaXplZCBieSBwdWJsaWNhdGlvbiBkYXRlIGFuZCBiaW5uZWQgaW50byB5ZWFyIGludGVydmFscyAobGltaXRlZCB0byB0aGUgdG9wIHRlbiksIHRoZSByZXN1bHRzIGFyZSBhcyBmb2xsb3dzOgoKYGBge3J9CmdfY29sb3JzIDwtIGh1ZXM6Oml3YW50aHVlKGRwbHlyOjpuX2Rpc3RpbmN0KGZ0X21hdGNoZXMkbWF0Y2gpKQoKZnRfbWF0Y2hlcyB8PgogICAgRE8udXRpbHM6OmNvbGxhcHNlX2NvbCgibWF0Y2hfbGMiKSB8PgogICAgZHBseXI6Om11dGF0ZShuID0gbGVuZ3RoKC5kYXRhJHNvdXJjZSksIC5ieSA9ICJtYXRjaCIpIHw+CiAgICBnZ3Bsb3QyOjpnZ3Bsb3QoKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2ZyZXFwb2x5KAogICAgICAgIGdncGxvdDI6OmFlcyh4ID0gcHViRGF0ZSwgY29sb3IgPSBtYXRjaCksCiAgICAgICAgYmlud2lkdGggPSAzNjUKICAgICkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGdfY29sb3JzKSArCiAgICBnZ3Bsb3QyOjpmYWNldF93cmFwKH4gc291cmNlLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpCmBgYAoKSG1tLi4uIHRoZSBvbGRlc3QgdXNlcyBhcmUgcXVpdGUgYSBsb25nIHRpbWUgYWdvIGFuZCBtYWtlIHRoZSBncmFwaCBhIGJpdCBoYXJkIHRvIHJlYWQuIFN1YnNldHRpbmcgdGhlIGdyYXBoIHRvIGFmdGVyIHRoZSB5ZWFyIDIwMDA6CmBgYHtyIHdhcm5pbmc9RkFMU0V9CmcgPC0gZnRfbWF0Y2hlcyB8PgogICAgRE8udXRpbHM6OmNvbGxhcHNlX2NvbCgibWF0Y2hfbGMiKSB8PgogICAgZHBseXI6Om11dGF0ZShuID0gbGVuZ3RoKC5kYXRhJHNvdXJjZSksIC5ieSA9ICJtYXRjaCIpIHw+CiAgICBnZ3Bsb3QyOjpnZ3Bsb3QoKSArCiAgICBnZ3Bsb3QyOjpnZW9tX2ZyZXFwb2x5KAogICAgICAgIGdncGxvdDI6OmFlcyh4ID0gcHViRGF0ZSwgY29sb3IgPSBtYXRjaCwgZ3JvdXAgPSBtYXRjaCksCiAgICAgICAgYmlud2lkdGggPSAzNjUsCiAgICAgICAgbGluZXdpZHRoID0gMQogICAgKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZ19jb2xvcnMpICsKICAgIGdncGxvdDI6OnNjYWxlX3hfZGF0ZSgKICAgICAgICBkYXRlX2JyZWFrcyA9ICI1IHllYXJzIiwKICAgICAgICBkYXRlX2xhYmVscyA9ICIlWSIKICAgICkgKwogICAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+IHNvdXJjZSwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICBnZ3Bsb3QyOjpjb29yZF9jYXJ0ZXNpYW4oCiAgICAgICAgeGxpbSA9IGMoYXMuRGF0ZSgiMjAwMC0wMS0wMSIpLCBhcy5EYXRlKCIyMDI1LTAxLTAxIikpCiAgICApICsKICAgIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKQoKcGxvdGx5OjpnZ3Bsb3RseShnKQpgYGAKCkJhc2VkIG9uIHRoaXMsIGl0J3MgdmVyeSBjbGVhciB0aGF0IHRoZSBjYXBpdGFsaXplZCB2ZXJzaW9uIG9mIHRoZSBvcmlnaW5hbCBuYW1lIGlzIG1vc3QgY29tbW9uLiBKdXN0IGxvb2tpbmcgYXQgdGhlIGRpc2Vhc2UgbmFtZSBqdXN0IHRvIGJlIHN1cmUgdGhpcyBpcyBhbHNvIHRoZSBjYXNlIGZvciB0aGUgZGlzZWFzZToKYGBge3Igd2FybmluZz1GQUxTRX0KZyA8LSBmdF9tYXRjaGVzIHw+CiAgICBkcGx5cjo6ZmlsdGVyKHN0cmluZ3I6OnN0cl9kZXRlY3QoLmRhdGEkbWF0Y2gsICJldmVyIikpIHw+CiAgICBETy51dGlsczo6Y29sbGFwc2VfY29sKCJtYXRjaF9sYyIpIHw+CiAgICBkcGx5cjo6bXV0YXRlKG4gPSBsZW5ndGgoLmRhdGEkc291cmNlKSwgLmJ5ID0gIm1hdGNoIikgfD4KICAgIGdncGxvdDI6OmdncGxvdCgpICsKICAgIGdncGxvdDI6Omdlb21fZnJlcXBvbHkoCiAgICAgICAgZ2dwbG90Mjo6YWVzKHggPSBwdWJEYXRlLCBjb2xvciA9IG1hdGNoLCBncm91cCA9IG1hdGNoKSwKICAgICAgICBiaW53aWR0aCA9IDM2NSwKICAgICAgICBsaW5ld2lkdGggPSAxCiAgICApICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBnX2NvbG9ycykgKwogICAgZ2dwbG90Mjo6c2NhbGVfeF9kYXRlKAogICAgICAgIGRhdGVfYnJlYWtzID0gIjUgeWVhcnMiLAogICAgICAgIGRhdGVfbGFiZWxzID0gIiVZIgogICAgKSArCiAgICBnZ3Bsb3QyOjpmYWNldF93cmFwKH4gc291cmNlLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKQoKcGxvdGx5OjpnZ3Bsb3RseShnKQpgYGAKCkEgZ2VuZXJhbCBzdW0gd291bGQgYmUgbW9yZSB1c2VmdWwgYnV0IHRoZSBkaWZmZXJlbmNlcyB0aGVyZSBhcmUgbmVnbGlnaWJsZS4gSW4gdGhpcyBjYXNlLCBpdCBtYWtlcyBzZW5zZSB0byBmb2xsb3cgdGhlIG1vc3QgY29tbW9uIG5hbWUgZm9yIHRoZSB2aXJ1cy4K